package com.ruoyi.project.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.hash.Hashing;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.TencentApi;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.framework.redis.RedisCache;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.system.domain.SysQuery;
import com.ruoyi.project.system.service.TencentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.Charsets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class TencentServiceImpl implements TencentService {

    @Value("${front-domain}")
    private String frontDomain;

    @Autowired
    private RedisCache redisCache;

    @Override
    public AjaxResult sendIdentityInfoUserInfo(String orderNo, SysQuery siyuQuery) throws Exception {
        AjaxResult result = new AjaxResult();
        // 1. 获取accessToken
        String accessToken = getAccessToken();
        if (accessToken == null) {
            throw new Exception("accessToken获取异常");
        }
        // 2. 获取signTicket
        String signTicket = getSignTicket(accessToken);
        if (signTicket == null) {
            throw new Exception("signTicket获取异常");
        }
        // 3. 合作方上送计算签名
        String userId = siyuQuery.getId().toString();
        orderNo += ("-" + UUID.randomUUID().toString().replace("-", "").substring(0, 8));
        result.put("orderNo", orderNo);
        List<String> list = new ArrayList<>();
        list.add("1.0.0");
        list.add(orderNo);
        list.add(userId);
        list.add(siyuQuery.getCardNo());
        list.add("IDAwv84P");
        list.add(signTicket);
        list.add(siyuQuery.getName());
        list.removeAll(Collections.singleton(null));
        Collections.sort(list);
        StringBuilder sb = new StringBuilder();
        for (String s : list) {
            sb.append(s);
        }
        String sign = Hashing.sha1().hashString(sb, Charsets.UTF_8).toString().toUpperCase();
        Map<String, String> param = new HashMap<>(16);
        param.put("appId", "IDAwv84P");
        param.put("orderNo", orderNo);
        param.put("name", siyuQuery.getName());
        param.put("idNo", siyuQuery.getCardNo());
        param.put("userId", userId);
        param.put("version", "1.0.0");
        param.put("sign", sign);
        String backStr = HttpUtils.sendPost("https://kyc1.qcloud.com/api/server/h5/geth5faceid?orderNo=" + orderNo, JSON.toJSONString(param));
        // 4.获取腾讯signTicket
        JSONObject backJson = JSONObject.parseObject(backStr);
        String nonceTicketValue = redisCache.getCacheObject("nonceTicketTencent");

        if (StringUtils.isEmpty(nonceTicketValue)) {
            String nonceTickeStr = HttpUtils.sendGet("https://kyc1.qcloud.com/api/oauth2/api_ticket?appId=IDAwv84P&access_token=" + accessToken + "&type=NONCE&version=1.0.0&user_id=" + userId);
            JSONObject jsonMap = JSONObject.parseObject(nonceTickeStr);
            if (!"0".equals(jsonMap.getString("code"))) {
                log.error("获取腾讯nonceTicket信息错误", jsonMap);
                return null;
            }
            nonceTicketValue = jsonMap.getJSONArray("tickets").getJSONObject(0).getString("value");
            redisCache.setCacheObject("nonceTicketTencent", nonceTicketValue, 100, TimeUnit.SECONDS);
        }
        // 5. 启动H5
        String nonce_ = UUID.randomUUID().toString().replace("-", "");
        String optimalDomain = backJson.getJSONObject("result").getString("optimalDomain");
        String h5faceId = backJson.getJSONObject("result").getString("h5faceId");

        List<String> openList = new ArrayList<>();
        openList.add("1.0.0");
        openList.add(orderNo);
        openList.add("IDAwv84P");
        openList.add(h5faceId);
        openList.add(nonce_);
        openList.add(userId);
        openList.add(nonceTicketValue);
        openList.removeAll(Collections.singleton(null));
        Collections.sort(openList);
        StringBuilder sb_ = new StringBuilder();
        for (String s : openList) {
            sb_.append(s);
        }
        String sign_ = Hashing.sha1().hashString(sb_, Charsets.UTF_8).toString().toUpperCase();
        String callBackUrl = frontDomain + "mar";
        result.put("url", "https://" + optimalDomain + "/api/pc/login?appId=IDAwv84P&version=1.0.0&nonce=" + nonce_ + "&orderNo=" + orderNo +
                "&h5faceId=" + h5faceId + "&url=" + URLEncoder.encode(callBackUrl, "UTF-8") + "&userId=" + userId + "&sign=" + sign_);
        return result;
    }

    @Override
    public String getAccessToken() {
        String accessToken = redisCache.getCacheObject("accessTokenTencent");
        if (StringUtils.isEmpty(accessToken)) {
            String jsonStr = HttpUtils.sendGet("https://kyc1.qcloud.com/api/oauth2/access_token?appId=IDAwv84P&secret=YQywZZCApFYjRfXWZq0zFHbfGzusDTUzYpQocH3abJQD5VrWJfyGT8XPCTYA1Ep6&grant_type=client_credential&version=1.0.0");
            log.warn("accessToken返回报文", jsonStr);
            JSONObject jsonMap = JSONObject.parseObject(jsonStr);
            if (!"0".equals(jsonMap.get("code"))) {
                return null;
            }
            accessToken = jsonMap.getString("access_token");
            // 过期时间 默认7200L  设置6800L提前重新获取
            redisCache.setCacheObject("accessTokenTencent", accessToken, 6800, TimeUnit.SECONDS);
        }
        return accessToken;
    }

    @Override
    public String getSignTicket(String accessToken) {
        String signTicket = redisCache.getCacheObject("signTicketTencent");
        if (StringUtils.isEmpty(signTicket)) {
            String jsonStr = HttpUtils.sendGet("https://kyc1.qcloud.com/api/oauth2/api_ticket?appId=IDAwv84P&access_token=" + accessToken + "&type=SIGN&version=1.0.0");
            JSONObject jsonMap = JSONObject.parseObject(jsonStr);
            log.warn("signTicket返回报文", jsonMap);
            if (!"0".equals(jsonMap.getString("code"))) {
                return null;
            }
            signTicket = jsonMap.getJSONArray("tickets").getJSONObject(0).getString("value");
            // 过期时间 默认3600L  设置3200L提前重新获取
            redisCache.setCacheObject("signTicketTencent", signTicket, 3000, TimeUnit.SECONDS);
        }
        return signTicket;
    }

    public String getOfficialAccountsAccessToken() {
        String jsonStr = HttpUtils.sendGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + TencentApi.appid + "&secret=" + TencentApi.secret);
        log.warn("officialAccountsAccessToken返回报文", jsonStr);
        JSONObject jsonMap = JSONObject.parseObject(jsonStr);
        String access_token = jsonMap.getString("access_token");
        // 过期时间 默认7200L  设置6800L提前重新获取
        redisCache.setCacheObject("officialAccountsAccessToken", access_token, 6800, TimeUnit.SECONDS);
        return access_token;
    }

    public JSONObject getTemporaryOfficialAccountsQRCode(Long userId) {
        String accessToken = redisCache.getCacheObject("officialAccountsAccessToken");
        if (StringUtils.isEmpty(accessToken)) {
            accessToken = getOfficialAccountsAccessToken();
        }
        JSONObject param = JSON.parseObject("{\"expire_seconds\": 604800, \"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": 0}}}");
        param.getJSONObject("action_info").getJSONObject("scene").replace("scene_id", userId);

        String backStr = HttpUtils.sendPost("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken, param);
        JSONObject backJson = JSON.parseObject(backStr);
        if (backJson.containsKey("errcode") && backJson.getInteger("errcode") == 40001) {
            for (int i = 0; i < 3; i++) {
                accessToken = getOfficialAccountsAccessToken();
                backStr = HttpUtils.sendPost("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken, param);
                backJson = JSON.parseObject(backStr);
                if (backJson.containsKey("url"))
                    break;
            }
        }
        return backJson;
    }

}
